﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

using System.Reflection;
using System.Runtime.InteropServices;

using Word = Microsoft.Office.Interop.Word; 

namespace OfficeUtilities
{
    public class WordReplace
    {

       /// <summary>
       /// 替换Word中的内容
       /// 
       /// [!string <symbo>] 替换字符串;
       /// 
       /// [!image <symbo>] 替换为图片;
       /// 
       /// </summary>
       /// <param name="filePath"></param>
       /// 


        public void setstring(string key, string Value)
        {
            Stringmap.Add(key, Value);
        }

        Dictionary<string, string> Stringmap = new Dictionary<string, string>();

        /// <summary>
        /// 生成文档
        /// </summary>
        /// <param name="TemplateFile">模板文件</param>
        /// <param name="outputPath">输出文件</param>
        /// <param name="visible">可见</param>
        /// <param name="savefile">保存</param>

        public void render(string TemplateFile, string outputPath,bool visible ,bool savefile)
        {

     
                // create word application
                Word.Application word = new Word.ApplicationClass();

                if (visible == true)
                {
                    word.Visible = true;
                }
                // create object of missing value
                object miss = System.Reflection.Missing.Value;
                // create object of selected file path
               // object path = filePath;
                // set file path mode
                //object readOnly = false;
                // open document                
                //Word._Document docs = word.Documents.Open(ref path, ref miss, ref readOnly, ref miss, ref miss, ref miss, ref miss, ref miss, ref miss, ref miss, ref miss, ref miss, ref miss, ref miss, ref miss, ref miss);

                object Template = TemplateFile;
               Word._Document docs = word.Documents.Add(
                    ref Template,//Template 可选 Variant 要用于新文档的模板名。如果省略该参数，则使用 Normal 模板。 
                    ref miss,//NewTemplate 可选 Variant 如果该属性值为 True，则将文档作为模板打开。默认值为 False。 
                    ref miss,//DocumentType 可选 Variant 可以是下列 WdNewDocumentType 常量之一：wdNewBlankDocument、wdNewEmailMessage、wdNewFrameset 或 wdNewWebPage。默认常量是 wdNewBlankDocument。 
                    ref miss//Visible 可选 Variant 如果该属性值为 True，将在可见窗口中打开文档。如果该属性值为 False，则 Microsoft Word 打开此文档，但将文档窗口的 Visible 属性设置为 False。默认值为 True。 
                        );

                //string a = string.Format("[!string {0}]", s);

                foreach (KeyValuePair<string, string> entry in Stringmap)
                {
                    string rep = string.Format("$#string {0}##", entry.Key);

                    findAndReplace(word, rep, entry.Value);
                    FindReplaceInSharp(word, rep, entry.Value);
                }

                if (savefile == true)
                {



                    object FileName = outputPath;
                    //wdFormatDocumentDefault 16 
                    object FileFormat = 16;
                    docs.SaveAs(
                        ref FileName,//FileName 可选 Variant 文档名称。默认值为当前文件夹和文件名。如果从未保存过此文档，则使用默认文件名（例如 Doc1.doc）。如果已经存在具有指定文件名的文档，则覆盖此文档，并且在覆盖前不提示用户。 
                        ref FileFormat,//FileFormat 可选 Variant 保存文档所用的格式。可以是任意 WdSaveFormat 常量。要以另一种格式保存文档，请为 FileConverter 对象的 SaveFormat 属性指定相应的值。 
                        ref miss,//LockComments 可选 Variant 如果该属性值为 True，则锁定文档备注。默认值为 False。 
                        ref miss,//Password 可选 Variant 打开文档所需的密码字符串（请参阅下面的“注解”）。 
                        ref miss,//AddToRecentFiles 可选 Variant 如果该属性值为 True，则将文档添加到“文件”菜单上最近使用的文件列表中。默认值为 True。 
                        ref miss,//WritePassword 可选 Variant 用于保存对文档的修改的密码字符串（请参阅下面的“注解”）。 
                        ref miss,//ReadOnlyRecommended 可选 Variant 如果该属性值为 True，则每次打开文档时，Microsoft Office Word 都将建议采用只读方式。默认值为 False。 
                        ref miss,//EmbedTrueTypeFonts 可选 Variant 如果该属性值为 True，则 TrueType 字体随文档一起保存。如果省略，则 EmbedTrueTypeFonts 参数将假定为 EmbedTrueTypeFonts 属性的值。 
                        ref miss,//SaveNativePictureFormat 可选 Variant 如果该属性值为 True，则对于从其他系统平台（如 Macintosh）导入的图形，只保存其 Microsoft Windows 版本。 
                        ref miss,//SaveFormsData 可选 Variant 如果该属性值为 True，则将用户在窗体中输入的数据保存为记录。 
                        ref miss,//SaveAsAOCELetter 可选 Variant 如果文档包含附加的邮件，当该属性值为 True 时，将文档存为 AOCE 信函（同时保存邮件）。 
                        ref miss,//Encoding 可选 MsoEncoding 用于另存为编码文本文件的文档的代码页或字符集。默认值为系统代码页。所有 MsoEncoding 常量均不能与该参数一同使用。 
                        ref miss,//InsertLineBreaks 可选 Variant 在将文档保存为文本文件时，如果该属性值为 True，则在每一行文本后插入换行符。 
                        ref miss,//AllowSubstitutions 可选 Variant 将文档保存为文本文件时，如果该属性值为 True，则 Word 可以将一些符号替换为相似的文本。例如，将版权符号显示为 (c)。默认值为 False。 
                        ref miss,//LineEnding 可选 Variant Word 在另存为文本文件的文档中标记换行符和分段符的方式。可以是下列 WdLineEndingType 常量之一：wdCRLF（默认值）或 wdCROnly。 
                        ref miss//AddBiDiMarks 可选 Variant 如果该属性值为 True，则为输出文件添加控制符，以保留原始文档中文本的双向版式。 
                        );

                }

                if (visible == false)
                {

                    // close the document
                    object save = -1; //wdSaveChanges
                    object OriginalFormat = 1; //wdOriginalDocumentFormat
                    //docs.Close(ref save, ref OriginalFormat, ref miss);

                    object saveOption = Word.WdSaveOptions.wdDoNotSaveChanges;
                    docs.Close(ref saveOption, ref miss, ref miss);
                    word.Quit(ref saveOption, ref miss, ref miss);

                }

        }

        object NmatchCase = false;
        object NmatchWholeWord = false;
        object NmatchWildCards = false;
        object NmatchSoundsLike = false;
        object NmatchAllWordFormd = false;
        object forward = true;
        object Nformat = true;
        object NmatchKashida = false;
        object NmatchDiacritics = false;
        object NmatchAlefHamza = false;
        object NmatchControl = false;
        object wrap = Word.WdFindWrap.wdFindContinue;


        public bool FindText(String filePath,
                            object findText)
        {
            // create word application
            Word.Application word = new Word.ApplicationClass();
            //word.Visible = true;
            object miss = System.Reflection.Missing.Value;
            object path = filePath;
            object readOnly = false;
            Word._Document docs = word.Documents.Open(ref path, ref miss, ref readOnly, ref miss, ref miss, ref miss, ref miss, ref miss, ref miss, ref miss, ref miss, ref miss, ref miss, ref miss, ref miss, ref miss);

            object replace = 0;

            bool t = word.Selection.Find.Execute(
                             ref findText,//FindText 可选 Variant 要搜索的文本。可用空字符串 ("") 仅搜索格式，也可通过指定相应的字符代码搜索特殊字符。例如，“^p”对应段落标记，“^t”对应制表符。 
                             ref NmatchCase,//MatchCase 可选 Variant 如果该属性值为 True，则指定查找文本区分大小写。相当于“编辑”菜单“查找和替换”对话框中的“区分大小写”复选框。 
                             ref NmatchWholeWord,//MatchWholeWord 可选 Variant 如果该属性值为 True，则查找操作只查找整个单词，而不查找长单词的一部分。相当于“查找和替换”对话框中的“全字匹配”复选框。 
                             ref NmatchWildCards,//MatchWildcards 可选 Variant 如果该属性值为 True，则查找的文字包含特殊搜索操作符。相当于“查找和替换”对话框中的“使用通配符”复选框。 
                             ref NmatchSoundsLike,//MatchSoundsLike 可选 Variant 如果该属性值为 True，则查找操作查找与要查找的文字发音相近的单词。相当于“查找和替换”对话框中的“同音”复选框。 
                             ref NmatchAllWordFormd,//MatchAllWordForms 可选 Variant 如果该属性值为 True，则查找操作查找要查找的文字的所有形式（例如，查找“sit”的同时，还查找“sitting”和“sat”），相当于“查找和替换”对话框中的“查找单词的所有形式”复选框。 
                             ref forward,//Forward 可选 Variant 如果该属性值为 True，则向下（向文档尾部）搜索。 
                             ref wrap, //Wrap 可选 Variant 如果从非文档起点处开始搜索并到达文档末尾（如 Forward 设置为 False 则相反），则用该参数控制接下来的操作。当存在选定内容或区域，而又没有在该选定内容或区域中找到搜索文字时，也可用该参数控制接下来的操作。可以是 WdFindWrap 常量之一。 
                             ref Nformat,//Format 可选 Variant 如果该属性值为 True，则查找操作定位于格式或带格式的文本，而不是查找文本。 
                             ref miss,//ReplaceWith 可选 Variant 替换文字。要删除由 Find 参数指定的文字，可使用空字符串 ("")。与 Find 参数相似，该参数也可以指定特殊的字符和高级搜索条件。要将图形对象或者其他非文本项指定为替换内容，可将这些项置于剪贴板上，然后将 ReplaceWith 指定为“^c”。 
                             ref replace, //Replace 可选 Variant 指定执行替换的个数：一个、全部或者不替换。可以是任意 WdReplace 常量。 
                                        //-----wdReplaceAll 2 替换所有匹配项。 wdReplaceNone 0 不替换任何匹配项。 wdReplaceOne 1 替换遇到的第一个匹配项。 
                             ref NmatchKashida, //MatchKashida 可选 Variant 在阿拉伯语文档中，如果查找操作用匹配的 kashida 来匹配文字，则该属性值为 True。根据您所选择或安装的语言支持（如美国英语）的不同，该参数可能不可用。 
                             ref NmatchDiacritics, //MatchDiacritics 可选 Variant 在使用从右向左语言的文档中，如果查找操作用匹配的音调符号来匹配文字，则该属性值为 True。根据您所选择或安装的语言支持（如美国英语）的不同，该参数可能不可用。 
                             ref NmatchAlefHamza, //MatchAlefHamza 可选 Variant 在阿拉伯语文档中，如果查找操作用匹配的 Alef Hamza 来匹配文字，则该属性值为 True。根据您所选择或安装的语言支持（如美国英语）的不同，该参数可能不可用。 
                             ref NmatchControl //MatchControl 可选 Variant 在使用从右向左语言的文档中，如果查找操作用匹配的双向控制字符来匹配文字，则该属性值为 True。根据您所选择或安装的语言支持（如美国英语）的不同，该参数可能不可用。 
                          );
            object save = true;
            docs.Close(ref save, ref miss, ref miss);
            return t;
        }

        private void findAndReplace(Word.Application WordApp,
                                    object findText,
                                    object replaceWithText)
        {
 
            object replace = 2;


            WordApp.Selection.Find.Execute(
                ref findText,//FindText 可选 Variant 要搜索的文本。可用空字符串 ("") 仅搜索格式，也可通过指定相应的字符代码搜索特殊字符。例如，“^p”对应段落标记，“^t”对应制表符。 
                ref NmatchCase,//MatchCase 可选 Variant 如果该属性值为 True，则指定查找文本区分大小写。相当于“编辑”菜单“查找和替换”对话框中的“区分大小写”复选框。 
                ref NmatchWholeWord,//MatchWholeWord 可选 Variant 如果该属性值为 True，则查找操作只查找整个单词，而不查找长单词的一部分。相当于“查找和替换”对话框中的“全字匹配”复选框。 
                ref NmatchWildCards,//MatchWildcards 可选 Variant 如果该属性值为 True，则查找的文字包含特殊搜索操作符。相当于“查找和替换”对话框中的“使用通配符”复选框。 
                ref NmatchSoundsLike,//MatchSoundsLike 可选 Variant 如果该属性值为 True，则查找操作查找与要查找的文字发音相近的单词。相当于“查找和替换”对话框中的“同音”复选框。 
                ref NmatchAllWordFormd,//MatchAllWordForms 可选 Variant 如果该属性值为 True，则查找操作查找要查找的文字的所有形式（例如，查找“sit”的同时，还查找“sitting”和“sat”），相当于“查找和替换”对话框中的“查找单词的所有形式”复选框。 
                ref forward,//Forward 可选 Variant 如果该属性值为 True，则向下（向文档尾部）搜索。 
                ref wrap, //Wrap 可选 Variant 如果从非文档起点处开始搜索并到达文档末尾（如 Forward 设置为 False 则相反），则用该参数控制接下来的操作。当存在选定内容或区域，而又没有在该选定内容或区域中找到搜索文字时，也可用该参数控制接下来的操作。可以是 WdFindWrap 常量之一。 
                ref Nformat,//Format 可选 Variant 如果该属性值为 True，则查找操作定位于格式或带格式的文本，而不是查找文本。 
                ref replaceWithText,//ReplaceWith 可选 Variant 替换文字。要删除由 Find 参数指定的文字，可使用空字符串 ("")。与 Find 参数相似，该参数也可以指定特殊的字符和高级搜索条件。要将图形对象或者其他非文本项指定为替换内容，可将这些项置于剪贴板上，然后将 ReplaceWith 指定为“^c”。 
                ref replace, //Replace 可选 Variant 指定执行替换的个数：一个、全部或者不替换。可以是任意 WdReplace 常量。 
                             //-----wdReplaceAll 2 替换所有匹配项。 wdReplaceNone 0 不替换任何匹配项。 wdReplaceOne 1 替换遇到的第一个匹配项。 
                ref NmatchKashida, //MatchKashida 可选 Variant 在阿拉伯语文档中，如果查找操作用匹配的 kashida 来匹配文字，则该属性值为 True。根据您所选择或安装的语言支持（如美国英语）的不同，该参数可能不可用。 
                ref NmatchDiacritics, //MatchDiacritics 可选 Variant 在使用从右向左语言的文档中，如果查找操作用匹配的音调符号来匹配文字，则该属性值为 True。根据您所选择或安装的语言支持（如美国英语）的不同，该参数可能不可用。 
                ref NmatchAlefHamza, //MatchAlefHamza 可选 Variant 在阿拉伯语文档中，如果查找操作用匹配的 Alef Hamza 来匹配文字，则该属性值为 True。根据您所选择或安装的语言支持（如美国英语）的不同，该参数可能不可用。 
                ref NmatchControl //MatchControl 可选 Variant 在使用从右向左语言的文档中，如果查找操作用匹配的双向控制字符来匹配文字，则该属性值为 True。根据您所选择或安装的语言支持（如美国英语）的不同，该参数可能不可用。 
                    //MatchPrefix 可选 Variant 如果该属性值为 True，则匹配以搜索字符串开头的单词。相当于“查找和替换”对话框中的“区分前缀”复选框。 
                    //MatchSuffix 可选 Variant 如果该属性值为 True，则匹配以搜索字符串结尾的单词。相当于“查找和替换”对话框中的“区分后缀”复选框。 
                    //MatchPhrase 可选 Variant 如果该属性值为 True，则忽略单词之间的所有空格和控制字符。 
                    //IgnoreSpace 可选 Variant 如果该属性值为 True，则忽略单词之间的所有空格。相当于“查找和替换”对话框中的“忽略空格”复选框。 
                    //IgnorePunct 可选 Variant 如果该属性值为 True，则忽略单词之间的所有标点符号。相当于“查找和替换”对话框中的“忽略标点符号”复选框。 
            );
        }

        /// <summary>
        /// 替换文本框中的文本
        /// </summary>
        /// <param name="WordApp"></param>
        /// <param name="findText"></param>
        /// <param name="replaceText"></param>
        private static void FindReplaceInSharp(Word.Application WordApp, string findText, string replaceText)
        {
            foreach (Word.Document doc in WordApp.Documents)
            {
                var shapes = doc.Shapes;

                foreach (Word.Shape shape in shapes)
                {
                    var initialText = shape.TextFrame.TextRange.Text;
                    var resultingText = initialText.Replace(findText, replaceText);
                    shape.TextFrame.TextRange.Text = resultingText;
                }
            }
        }
    }
}

/* 复制
                docs.ActiveWindow.Selection.WholeStory();
                // handover the data to cllipboard
                docs.ActiveWindow.Selection.Copy();
                // clipboard create reference of idataobject interface which transfer the data
                IDataObject data = Clipboard.GetDataObject();
                //set data into richtextbox control in text format
                richTextBox2.Text = data.GetData(DataFormats.Text).ToString();
                // read bitmap image from clipboard with help of iddataobject interface
                Image img = (Image)data.GetData(DataFormats.Bitmap);
 */